-
Notifications
You must be signed in to change notification settings - Fork 243
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Filter duplicate extensions by src URL #1192
Conversation
Testing PHP implementation: ampproject/amp-toolbox-php#130 |
<link rel="preload" href="https://cdn.ampproject.org/v0.css" as="style"> | ||
<link href="https://fonts.googleapis.com/css?foobar" rel="stylesheet" type="text/css"> | ||
<link as="script" crossorigin="anonymous" href="https://cdn.ampproject.org/v0.mjs" rel="modulepreload"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the link[rel=preload]
and link[rel=modulepreload]
be moved to the beginning of the head
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
Here's the current order in the PHP implementation: <link as="script" crossorigin="anonymous" href="https://cdn.ampproject.org/v0.mjs" rel="modulepreload">
<link rel="preload" href="https://cdn.ampproject.org/v0.css" as="style">
<link rel="stylesheet" href="https://cdn.ampproject.org/v0.css">
<script async nomodule src="https://cdn.ampproject.org/v0.js"></script>
<script async src="https://cdn.ampproject.org/v0.mjs" type="module" crossorigin="anonymous"></script>
<script async nomodule src="https://cdn.ampproject.org/v0/amp-experiment-0.1.js" custom-element="amp-experiment"></script>
<script async custom-element="amp-experiment" src="https://cdn.ampproject.org/v0/amp-experiment-0.1.mjs" type="module" crossorigin="anonymous"></script>
<script async="" nomodule="" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js" custom-template="amp-mustache"></script>
<script async="" custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.mjs" type="module" crossorigin="anonymous"></script>
<link href="https://example.com/favicon.ico" rel="icon">
<link href="https://fonts.googleapis.com/css?foobar" rel="stylesheet" type="text/css"> When outputting AMP scripts, it seems that the |
Not sure if that really makes a difference. I'd assume that the browser will simply ignore the |
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.mjs" type="module" crossorigin="anonymous"></script> | ||
<link href="https://example.com/favicon.ico" rel="icon"> | ||
<link href="https://fonts.googleapis.com/css?foobar" rel="stylesheet" type="text/css"> | ||
<link as="script" crossorigin="anonymous" href="https://cdn.ampproject.org/v0.mjs" rel="modulepreload"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This modulepreload
link needs to be moved up along with the preload
as well. Ref ampproject/amp-toolbox-php@a3a99fd
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patience taking it up with my empty brain today...
<!doctype html> | ||
<html ⚡> | ||
<head> | ||
<script async nomodule src="https://cdn.ampproject.org/v0.js"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Big problem: The nomodule
v0.js script is getting dropped in the output. Here's one thing I had to do in the PHP version to account for this: ampproject/amp-toolbox-php@4bad718
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
<link as="script" crossorigin="anonymous" href="https://cdn.ampproject.org/v0.mjs" rel="modulepreload"> | ||
<link rel="preload" href="https://cdn.ampproject.org/v0.css" as="style"> | ||
<link rel="stylesheet" href="https://cdn.ampproject.org/v0.css"> | ||
<script async src="https://cdn.ampproject.org/v0.mjs" type="module" crossorigin="anonymous"></script> |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
Can we go ahead and do that so that there is consistency in the ordering? I've implemented this in the PHP version now. The PHP version now generates the <link as="script" crossorigin="anonymous" href="https://cdn.ampproject.org/v0.mjs" rel="modulepreload">
<link rel="preload" href="https://cdn.ampproject.org/v0.css" as="style">
<link rel="stylesheet" href="https://cdn.ampproject.org/v0.css">
<script async src="https://cdn.ampproject.org/v0.mjs" type="module" crossorigin="anonymous"></script>
<script async nomodule src="https://cdn.ampproject.org/v0.js"></script>
<script async custom-element="amp-experiment" src="https://cdn.ampproject.org/v0/amp-experiment-0.1.mjs" type="module" crossorigin="anonymous"></script>
<script async nomodule src="https://cdn.ampproject.org/v0/amp-experiment-0.1.js" custom-element="amp-experiment"></script>
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.mjs" type="module" crossorigin="anonymous"></script>
<script async nomodule src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js" custom-template="amp-mustache"></script>
<link href="https://example.com/favicon.ico" rel="icon">
<link href="https://fonts.googleapis.com/css?foobar" rel="stylesheet" type="text/css"> This ordering aligns with the AMP boilerplate usage as well, where we have |
The PHP version is also sorting the script components by name, so |
_removeDuplicateCustomExtensions(extensions) { | ||
const nodesByName = new Map(); | ||
const nodesBySrc = new Map(); | ||
for (const node of extensions) { | ||
const name = this._getName(node); | ||
nodesByName.set(name, node); | ||
const src = node.attribs['src']; | ||
nodesBySrc.set(src, node); | ||
} | ||
return Array.from(nodesByName.values()); | ||
return Array.from(nodesBySrc.values()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I took an alternative approach to this in PHP, to do the deduplication in the registerScript
function itself: https://github.com/ampproject/amp-toolbox-php/pull/130/files#diff-b0da2cc892f74bf1ebc7a84e63d7065894b24541a48f3a26089f23860ee1209fR156-R190
This also accounts for module
and nomodule
variations.
for (const node of extensions) { | ||
const name = this._getName(node); | ||
nodesByName.set(name, node); | ||
const src = node.attribs['src']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this remove the host to make sure a same extension is not downloaded twice from two different hosts?
<script async nomodule src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js" custom-template="amp-mustache"></script> | ||
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.mjs" type="module" crossorigin="anonymous"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the order be reversed, with the nomodule
one coming after?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
@@ -100,31 +96,39 @@ class HeadNodes { | |||
} | |||
|
|||
_registerScript(node) { | |||
const moduleIndex = hasAttribute(node, 'nomodule') ? 0 : 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should ensure nomodule
comes after type=module
.
const moduleIndex = hasAttribute(node, 'nomodule') ? 0 : 1; | |
const moduleIndex = hasAttribute(node, 'nomodule') ? 1 : 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed the feedback. Scripts should now have the right order.
Not super happy about the changes as the implementation is now more complex (and expensive) than before (without a real need, as the module scripts are injected in a later stage of the transformation).
<script async nomodule src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js" custom-template="amp-mustache"></script> | ||
<script async custom-template="amp-mustache" src="https://cdn.ampproject.org/v0/amp-mustache-0.2.mjs" type="module" crossorigin="anonymous"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
<!doctype html> | ||
<html ⚡> | ||
<head> | ||
<script async nomodule src="https://cdn.ampproject.org/v0.js"></script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
appendAll(head, this._metaOther); | ||
appendAll(head, this._resourceHintLinks); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The metaOther
can potentially includes lots of non-critical stuff like OpenGraph tags. I think in terms of performance, the resource hints should come right after the charset and before these other meta tags.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point! done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still wondering about the following priorities:
- ) Is the viewport needed for making decisions about the resource hints? I don't think so, but I'm not entirely sure.
- ) The boilerplate style is now much further down, after the scripts. Are we sure this does not lead to FOUC?
// needs to run after ReorderHeadTransformer | ||
'RewriteAmpUrls', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// needs to run after ReorderHeadTransformer | |
'RewriteAmpUrls', | |
'RewriteAmpUrls', |
// needs to run after ReorderHeadTransformer | ||
'RewriteAmpUrls', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// needs to run after ReorderHeadTransformer | |
'RewriteAmpUrls', | |
'RewriteAmpUrls', |
// needs to run after ReorderHeadTransformer | ||
'RewriteAmpUrls', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// needs to run after ReorderHeadTransformer | |
'RewriteAmpUrls', | |
'RewriteAmpUrls', |
re 1) Yes, viewport needs to come first (I think that was the reason why I added |
Hm. Following that logic, we should also move |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I defer to @schlessera.
Thanks a lot for the patience and detailed review! |
Fixes #1191